{
 "metadata": {
  "signature": "sha256:c04f3e842251d3dce6e01fb31ede08c05845753f26ac23760b97244df03ffb9c"
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Vtk volume rendering\n",
      "====================\n",
      "\n",
      "As I had some problems in figuring out how to use VTK to render data\n",
      "contained in a three dimensional numpy array, I have decided to share my\n",
      "code. This code is based on the otherwise excellent documentation for\n",
      "VTK and the now outdated vtkImageImportFromArray-class created by David\n",
      "Gobbi found at\n",
      "<http://public.kitware.com/cgi-bin/cvsweb.cgi/vtk/python/?cvsroot=vtk>\n",
      "\n",
      "The example is very simple, for more advanced functionality: read the\n",
      "documentation."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import vtk\n",
      "from numpy import *\n",
      "\n",
      "# We begin by creating the data we want to render.\n",
      "# For this tutorial, we create a 3D-image containing three overlaping cubes. \n",
      "# This data can of course easily be replaced by data from a medical CT-scan or anything else three dimensional.\n",
      "# The only limit is that the data must be reduced to unsigned 8 bit or 16 bit integers.\n",
      "data_matrix = zeros([75, 75, 75], dtype=uint8)\n",
      "data_matrix[0:35, 0:35, 0:35] = 50\n",
      "data_matrix[25:55, 25:55, 25:55] = 100\n",
      "data_matrix[45:74, 45:74, 45:74] = 150\n",
      "\n",
      "# For VTK to be able to use the data, it must be stored as a VTK-image. This can be done by the vtkImageImport-class which\n",
      "# imports raw data and stores it. \n",
      "dataImporter = vtk.vtkImageImport()\n",
      "# The preaviusly created array is converted to a string of chars and imported.\n",
      "data_string = data_matrix.tostring()\n",
      "dataImporter.CopyImportVoidPointer(data_string, len(data_string))\n",
      "# The type of the newly imported data is set to unsigned char (uint8)\n",
      "dataImporter.SetDataScalarTypeToUnsignedChar()\n",
      "# Because the data that is imported only contains an intensity value (it isnt RGB-coded or someting similar), the importer\n",
      "# must be told this is the case.\n",
      "dataImporter.SetNumberOfScalarComponents(1)\n",
      "# The following two functions describe how the data is stored and the dimensions of the array it is stored in. For this\n",
      "# simple case, all axes are of length 75 and begins with the first element. For other data, this is probably not the case.\n",
      "# I have to admit however, that I honestly dont know the difference between SetDataExtent() and SetWholeExtent() although\n",
      "# VTK complains if not both are used.\n",
      "dataImporter.SetDataExtent(0, 74, 0, 74, 0, 74)\n",
      "dataImporter.SetWholeExtent(0, 74, 0, 74, 0, 74)\n",
      "\n",
      "# The following class is used to store transparencyv-values for later retrival. In our case, we want the value 0 to be\n",
      "# completly opaque whereas the three different cubes are given different transperancy-values to show how it works.\n",
      "alphaChannelFunc = vtk.vtkPiecewiseFunction()\n",
      "alphaChannelFunc.AddPoint(0, 0.0)\n",
      "alphaChannelFunc.AddPoint(50, 0.05)\n",
      "alphaChannelFunc.AddPoint(100, 0.1)\n",
      "alphaChannelFunc.AddPoint(150, 0.2)\n",
      "\n",
      "# This class stores color data and can create color tables from a few color points. For this demo, we want the three cubes\n",
      "# to be of the colors red green and blue.\n",
      "colorFunc = vtk.vtkColorTransferFunction()\n",
      "colorFunc.AddRGBPoint(50, 1.0, 0.0, 0.0)\n",
      "colorFunc.AddRGBPoint(100, 0.0, 1.0, 0.0)\n",
      "colorFunc.AddRGBPoint(150, 0.0, 0.0, 1.0)\n",
      "\n",
      "# The preavius two classes stored properties. Because we want to apply these properties to the volume we want to render,\n",
      "# we have to store them in a class that stores volume prpoperties.\n",
      "volumeProperty = vtk.vtkVolumeProperty()\n",
      "volumeProperty.SetColor(colorFunc)\n",
      "volumeProperty.SetScalarOpacity(alphaChannelFunc)\n",
      "\n",
      "# This class describes how the volume is rendered (through ray tracing).\n",
      "compositeFunction = vtk.vtkVolumeRayCastCompositeFunction()\n",
      "# We can finally create our volume. We also have to specify the data for it, as well as how the data will be rendered.\n",
      "volumeMapper = vtk.vtkVolumeRayCastMapper()\n",
      "volumeMapper.SetVolumeRayCastFunction(compositeFunction)\n",
      "volumeMapper.SetInputConnection(dataImporter.GetOutputPort())\n",
      "\n",
      "# The class vtkVolume is used to pair the preaviusly declared volume as well as the properties to be used when rendering that volume.\n",
      "volume = vtk.vtkVolume()\n",
      "volume.SetMapper(volumeMapper)\n",
      "volume.SetProperty(volumeProperty)\n",
      "\n",
      "# With almost everything else ready, its time to initialize the renderer and window, as well as creating a method for exiting the application\n",
      "renderer = vtk.vtkRenderer()\n",
      "renderWin = vtk.vtkRenderWindow()\n",
      "renderWin.AddRenderer(renderer)\n",
      "renderInteractor = vtk.vtkRenderWindowInteractor()\n",
      "renderInteractor.SetRenderWindow(renderWin)\n",
      "\n",
      "# We add the volume to the renderer ...\n",
      "renderer.AddVolume(volume)\n",
      "# ... set background color to white ...\n",
      "renderer.SetBackground(1, 1, 1)\n",
      "# ... and set window size.\n",
      "renderWin.SetSize(400, 400)\n",
      "\n",
      "# A simple function to be called when the user decides to quit the application.\n",
      "def exitCheck(obj, event):\n",
      "    if obj.GetEventPending() != 0:\n",
      "        obj.SetAbortRender(1)\n",
      "\n",
      "# Tell the application to use the function as an exit check.\n",
      "renderWin.AddObserver(\"AbortCheckEvent\", exitCheck)\n",
      "\n",
      "renderInteractor.Initialize()\n",
      "# Because nothing will be rendered without any input, we order the first render manually before control is handed over to the main-loop.\n",
      "renderWin.Render()\n",
      "renderInteractor.Start()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "To exit the application, simply press *q*.\n",
      "\n",
      "In my opinion, the volume renderer creates extremely ugly images if not\n",
      "the following option is used:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "volumeProperty.ShadeOn()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    }
   ],
   "metadata": {}
  }
 ]
}